
package analisadores;

/**
 *
 * @author elias
 * @author eduardo
 */
public class lexico {

    //transformando método reconhece em funcionamento de um autômato
    
    private char[] arquivo;
    private int numline = 1;
    private int numcaracter = 0;
    private boolean isAtEnd = false;

    public lexico(String diretorio){
        String nothing = "";
        boolean b = true;
        try{
            java.io.BufferedReader bf = new java.io.BufferedReader(new java.io.FileReader(new java.io.File(diretorio)));
            while(bf.ready()){
                if ( !b )
                    nothing = nothing + "\n" + bf.readLine();
                else{
                    nothing += bf.readLine();
                    b = false;
                }
            }
            this.arquivo = nothing.toCharArray();
            //System.out.println(arquivo);
        }catch(Exception ex){
            System.err.println("Erro: "+ex.getMessage());
            System.exit(1);
        }
    }

    public Token next(){
        while ( this.isSeparator() );
        int posAtual = this.numcaracter;
        //System.out.println("posAtual: "+posAtual+" numcaracter: "+this.numcaracter+" arquivosize: "+this.arquivo.length);
        int tipo = this.reconhece();
        String tok = "";
        for (int i = posAtual; i < this.numcaracter; ++i){
            tok+=this.arquivo[i];
        }
        tok = (tipo == 0)?"EOF":tok;
        tok = (tipo == -1)?"ERRO":tok;
        Token tk = new Token(tok, tipo);
        return tk;
    }

    private boolean ehEspaco(){
        return ( atual() == ' ');
    }

    private boolean ehNovaLinha(){
        return ( atual() == '\n');
    }

    private boolean isSeparator(){
        if ( isAtEnd )
            return false;
        if ( ehEspaco() ){
            this.numcaracter++;
            return true;
        }
        if ( ehNovaLinha() ){
            this.numcaracter++;
            this.numline++;
            return true;
        }
        if ( atual() == '/' ){
            this.numcaracter++;
            if ( atual() == '/' ){
                while(true){
                    if ( isAtEnd ){
                        return false;
                    }
                    if ( atual() == '\n' ){
                            this.numcaracter++;
                            this.numline++;
                            return true;
                    }
                    this.numcaracter++;
                }
            }else{
                this.numcaracter--;
                return false;
            }
        }
        if ( atual() == '#' ){
            this.numcaracter++;
            if ( atual() =='{' ){
                this.numcaracter++;
                while(true){
                    if ( this.isAtEnd ) {
                        System.err.println("Linha: "+this.numline+" Abertura comentário sem fechamento!");
                        return false;
                    }
                    if ( atual() == '}' ){
                        this.numcaracter++;
                        if ( atual() == '#' ) {
                            this.numcaracter++;
                            break;
                        }else
                            this.numcaracter--;
                    }
                    this.numcaracter++;
                }
            }
            return true;
        }
        return false;
    }

private int reconhece(){
        if ( this.isAtEnd ){
            return 0;
        }
        if ( atual() == '~' ){
            this.numcaracter++;
            if ( atual() == '=' ){
                this.numcaracter++;
                return Token.NOT_EQUAL;
            }
            return Token.NEGACAO;
        }
        if ( atual() == '>' ) {
            this.numcaracter++;
            if ( atual() == '=' ){
                this.numcaracter++;
                return Token.GREATER_EQUAL;
            }
            return Token.GREATER;
        }
        if ( atual() == '<' ){
            this.numcaracter++;
            if ( atual() == '=' ){
                this.numcaracter++;
                return Token.LESSER_EQUAL;
            }
            return Token.LESSER;
        }
        if ( atual() == '=' ){
            this.numcaracter++;
            if ( atual() == '=' ){
                this.numcaracter++;
                return Token.EQUAL;
            }
            return Token.ATRIBUICAO;
        }
        if ( atual() == '&' ){
            this.numcaracter++;
            if ( atual() == '&' ){
                this.numcaracter++;
                return Token.AND;
            }
            return Token.LOGIC_AND;
        }
        if ( atual() == '|' ){
            this.numcaracter++;
            if ( atual() == '|' ){
                this.numcaracter++;
                return Token.OR;
            }
            return Token.LOGIC_OR;
        }
        if ( atual() == '+'){
            this.numcaracter++;
            return Token.ADICAO;
        }
        if ( atual() == '-'){
            this.numcaracter++;
            return Token.SUBTRACAO;
        }
        if ( atual() == '*'){
            this.numcaracter++;
            return Token.MULTIPLICACAO;
        }
        if ( atual() == '/'){
            this.numcaracter++;
            return Token.DIVISAO;
        }
        if ( atual() == '^'){
            this.numcaracter++;
            return Token.EXPONENCIAL;
        }
        if ( atual() == '%' ){
            this.numcaracter++;
            return Token.MODULO;
        }
        if ( atual() == '(' ){
            this.numcaracter++;
            return Token.LPAREN;
        }
        if ( atual() == ')' ){
            this.numcaracter++;
            return Token.RPAREN;
        }
        if ( atual() == '{' ){
            this.numcaracter++;
            return Token.LCHAVE;
        }
        if ( atual() == '}' ){
            this.numcaracter++;
            return Token.RCHAVE;
        }
        if ( atual() == 'i'){
            this.numcaracter++;
            if ( atual() == 'n'){
                this.numcaracter++;
                if ( atual() == 't'){
                    this.numcaracter++;
                    if ( ehEspaco() || ehNovaLinha() ){
                        return Token.INTEIRO;
                    }else{
                        while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                            this.numcaracter++;
                        return Token.IDENTIFICADOR;
                    }
                }
                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                    this.numcaracter++;
                return Token.IDENTIFICADOR;
            }
            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                this.numcaracter++;
            return Token.IDENTIFICADOR;
        }
        if ( atual() == 's'){
            this.numcaracter++;
            if ( atual() == 't'){
                this.numcaracter++;
                if ( atual() == 'r'){
                    this.numcaracter++;
                    if ( ehEspaco() || ehNovaLinha() ){
                        return Token.STRING;
                    }else{
                        while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                            this.numcaracter++;
                        return Token.IDENTIFICADOR;
                    }
                }
                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                    this.numcaracter++;
                return Token.IDENTIFICADOR;
            }
            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                this.numcaracter++;
            return Token.IDENTIFICADOR;
        }
        if ( atual() == 'c'){
            this.numcaracter++;
            if ( atual() == 'h'){
                this.numcaracter++;
                if ( atual() == 'a'){
                    this.numcaracter++;
                    if ( atual() == 'r'){
                        this.numcaracter++;
                        if ( ehEspaco() || ehNovaLinha() ){
                            return Token.CHAR;
                        }else{
                            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                                this.numcaracter++;
                            return Token.IDENTIFICADOR;
                        }
                    }
                    while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                        this.numcaracter++;
                    return Token.IDENTIFICADOR;
                }
                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                    this.numcaracter++;
                return Token.IDENTIFICADOR;
            }
            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                this.numcaracter++;
            return Token.IDENTIFICADOR;
        }
        if ( atual() == 'v'){
            this.numcaracter++;
            if ( atual() == 'o'){
                this.numcaracter++;
                if ( atual() == 'i'){
                    this.numcaracter++;
                    if ( atual() == 'd'){
                        this.numcaracter++;
                        if ( ehEspaco() || ehNovaLinha() ){
                            return Token.VOID;
                        }else{
                            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                                this.numcaracter++;
                            return Token.IDENTIFICADOR;
                        }
                    }
                    while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                        this.numcaracter++;
                    return Token.IDENTIFICADOR;
                }
                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                    this.numcaracter++;
                return Token.IDENTIFICADOR;
            }
            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                this.numcaracter++;
            return Token.IDENTIFICADOR;
        }
        if ( atual() == 't'){
            this.numcaracter++;
            if ( atual() == 'r'){
                this.numcaracter++;
                if ( atual() == 'u'){
                    this.numcaracter++;
                    if ( atual() == 'e'){
                        this.numcaracter++;
                        if ( ehEspaco() || ehNovaLinha() ){
                            return Token.TRUE;
                        }else{
                            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                                this.numcaracter++;
                            return Token.IDENTIFICADOR;
                        }
                    }
                    while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                        this.numcaracter++;
                    return Token.IDENTIFICADOR;
                }
                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                    this.numcaracter++;
                return Token.IDENTIFICADOR;
            }
            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                this.numcaracter++;
            return Token.IDENTIFICADOR;
        }
        if ( atual() == 'f'){
            this.numcaracter++;
            if ( atual() == 'a'){
                this.numcaracter++;
                if ( atual() == 'l'){
                    this.numcaracter++;
                    if ( atual() == 's'){
                        this.numcaracter++;
                        if ( atual() == 'e'){
                            this.numcaracter++;
                            if ( ehEspaco() || ehNovaLinha() ){
                                return Token.FALSE;
                            }else{
                                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                                    this.numcaracter++;
                                return Token.IDENTIFICADOR;
                            }
                        }
                        while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                            this.numcaracter++;
                        return Token.IDENTIFICADOR;
                    }
                    while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                        this.numcaracter++;
                    return Token.IDENTIFICADOR;
                }
                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                    this.numcaracter++;
                return Token.IDENTIFICADOR;
            }
            if ( atual() == 'l'){
                this.numcaracter++;
                if ( atual() == 'o'){
                    this.numcaracter++;
                    if ( atual() == 'a'){
                        this.numcaracter++;
                        if ( atual() == 't'){
                            this.numcaracter++;
                            if ( ehEspaco() || ehNovaLinha() ){
                                return Token.FLOAT;
                            }else{
                                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                                    this.numcaracter++;
                                return Token.IDENTIFICADOR;
                            }
                        }
                        while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                            this.numcaracter++;
                        return Token.IDENTIFICADOR;
                    }
                    while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                        this.numcaracter++;
                    return Token.IDENTIFICADOR;
                }
                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                    this.numcaracter++;
                return Token.IDENTIFICADOR;
            }
            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                this.numcaracter++;
            return Token.IDENTIFICADOR;
        }
        if ( atual() == 'b'){
            this.numcaracter++;
            if ( atual() == 'o'){
                this.numcaracter++;
                if ( atual() == 'o'){
                    this.numcaracter++;
                    if ( atual() == 'l'){
                        this.numcaracter++;
                        if ( atual() == 'e'){
                            this.numcaracter++;
                            if ( atual() == 'a'){
                                this.numcaracter++;
                                if ( atual() == 'n'){
                                    this.numcaracter++;
                                    if ( ehEspaco() || ehNovaLinha() ){
                                        return Token.BOOLEAN;
                                    }else{
                                        while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                                            this.numcaracter++;
                                        return Token.IDENTIFICADOR;
                                    }
                                }
                                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                                    this.numcaracter++;
                                return Token.IDENTIFICADOR;
                            }
                            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                                this.numcaracter++;
                            return Token.IDENTIFICADOR;
                        }
                        while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                            this.numcaracter++;
                        return Token.IDENTIFICADOR;
                    }
                    while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                        this.numcaracter++;
                    return Token.IDENTIFICADOR;
                }
                while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                    this.numcaracter++;
                return Token.IDENTIFICADOR;
            }
            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                this.numcaracter++;
            return Token.IDENTIFICADOR;
        }
        if ( Character.isDigit(atual()) ){
            while( !isAtEnd && Character.isDigit(atual()) )
                this.numcaracter++;
            return Token.DIGITO;
        }
        if ( isMinimo(atual())){
            while( !isAtEnd && ( atual() == '_' || Character.isDigit(atual()) || isValido(atual())) )
                this.numcaracter++;
            return Token.IDENTIFICADOR;
        }
        //caracter indefinido
        this.numcaracter++;
        return -1;
    }

    public boolean hasNext(){
        return !this.isAtEnd;
    }

    private char atual(){
        if ( this.numcaracter >= this.arquivo.length ){
            this.isAtEnd = true;
            return ' ';
        }
        return (this.arquivo[this.numcaracter]);
    }

    private static boolean isMinimo(char c){
        return ( c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e'
                 || c == 'f' || c == 'g' || c == 'h' || c == 'i' || c == 'j'
                  || c == 'k' || c == 'l' || c == 'm' || c == 'n' || c == 'o'
                   || c == 'p' || c == 'q' || c == 'r' || c == 's' || c == 't'
                    || c == 'u' || c == 'v' || c == 'w' || c == 'x' || c == 'y' || c == 'z');
    }

    private static boolean isValido(char c){
        return ( c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e'
                 || c == 'f' || c == 'g' || c == 'h' || c == 'i' || c == 'j'
                  || c == 'k' || c == 'l' || c == 'm' || c == 'n' || c == 'o'
                   || c == 'p' || c == 'q' || c == 'r' || c == 's' || c == 't'
                    || c == 'u' || c == 'v' || c == 'w' || c == 'x' || c == 'y' || c == 'z'
                || c == 'A' || c == 'B' || c == 'C' || c == 'D' || c == 'E'
                 || c == 'F' || c == 'G' || c == 'H' || c == 'I' || c == 'J'
                  || c == 'K' || c == 'L' || c == 'M' || c == 'N' || c == 'O'
                   || c == 'P' || c == 'Q' || c == 'R' || c == 'S' || c == 'T'
                    || c == 'U' || c == 'V' || c == 'W' || c == 'X' || c == 'Y' || c == 'Z');
    }

}
